package com.zilue.hfqueue.queue.index;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 数据结构
 * 读索引 /blockID/读索引下标位置/
 * 写索引 /blockID/写索引下标位置/
 * Created by ZD on 2017/5/3.
 */
public class HFQueueIndex {
    private final int READ_BLOCK_POSITION = 8;
    private final int READ_NUMBER_POSITION = 12;
    private final int READ_INDEX_POSITION = 16;
    private final int WRITE_BLOCK_POSITION = 20;
    private final int WRITE_NUMBER_POSITION = 24;
    private final int WRITE_INDEX_POSITION = 28;
    private final int INDEX_START_POSITION = 0;
    private final int INDEX_END_POSITION = 32;
    private final String POSTFIX = ".index";
    private RandomAccessFile file;
    private MappedByteBuffer buffer;
    private AtomicInteger read_block = new AtomicInteger(0);
    private AtomicInteger read_number = new AtomicInteger(0);
    private AtomicInteger read_index = new AtomicInteger(0);
    private AtomicInteger write_block = new AtomicInteger(0);
    private AtomicInteger write_number = new AtomicInteger(0);
    private AtomicInteger write_index = new AtomicInteger(0);

    public HFQueueIndex(String path, String topic) throws IOException {
        file = new RandomAccessFile(path + "HFQueue-" + topic + POSTFIX, "rw");
        buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, INDEX_START_POSITION, INDEX_END_POSITION).force();
        read_block.set(buffer.getInt(READ_BLOCK_POSITION));
        read_number.set(buffer.getInt(READ_NUMBER_POSITION));
        read_index.set(buffer.getInt(READ_INDEX_POSITION));
        write_block.set(buffer.getInt(WRITE_BLOCK_POSITION));
        write_number.set(buffer.getInt(WRITE_NUMBER_POSITION));
        write_index.set(buffer.getInt(WRITE_INDEX_POSITION));
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                buffer.force();
                try {
                    if (file != null)
                        file.close();
                } catch (IOException e) {
                    System.err.println("关闭文件失败");
                    throw new RuntimeException(e);
                }
            }
        }));
    }

    public void close(){
        buffer.force();
        try {
            if (file != null)
                file.close();
        } catch (IOException e) {
            System.err.println("关闭文件失败");
            throw new RuntimeException(e);
        }
    }

    public void updateReadIndex(int readIndex) {
        read_index.compareAndSet(read_index.get(), readIndex);
        buffer.position(READ_INDEX_POSITION);
        buffer.putInt(readIndex);
    }

    public void updateReadNumber(int number) {
        read_number.compareAndSet(read_number.get(), number);
        buffer.position(READ_NUMBER_POSITION);
        buffer.putInt(number);
    }

    public void updateReadBlock(int readBlock) {
        read_block.compareAndSet(read_block.get(), readBlock);
        buffer.position(READ_BLOCK_POSITION);
        buffer.putInt(readBlock);
        updateReadIndex(0);
    }

    public void updateWriteIndex(int writeIndex) {
        write_index.compareAndSet(write_index.get(), writeIndex);
        buffer.position(WRITE_INDEX_POSITION);
        buffer.putInt(writeIndex);
    }

    public void updateWriteNumber(int number) {
        write_number.compareAndSet(write_number.get(), number);
        buffer.position(WRITE_NUMBER_POSITION);
        buffer.putInt(number);
    }

    public void updateWriteBlock(int writeBlock) {
        write_block.compareAndSet(write_block.get(), writeBlock);
        buffer.position(WRITE_BLOCK_POSITION);
        buffer.putInt(writeBlock);
        updateWriteIndex(0);
    }

    public AtomicInteger getRead_block() {
        return read_block;
    }

    public void setRead_block(AtomicInteger read_block) {
        this.read_block = read_block;
    }

    public AtomicInteger getRead_index() {
        return read_index;
    }

    public void setRead_index(AtomicInteger read_index) {
        this.read_index = read_index;
    }

    public AtomicInteger getWrite_block() {
        return write_block;
    }

    public void setWrite_block(AtomicInteger write_block) {
        this.write_block = write_block;
    }

    public AtomicInteger getWrite_index() {
        return write_index;
    }

    public AtomicInteger getRead_number() {
        return read_number;
    }

    public AtomicInteger getWrite_number() {
        return write_number;
    }

    public void setWrite_index(AtomicInteger write_index) {
        this.write_index = write_index;
    }






}
